/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package yoga.algo.coding.binary;

import yoga.algo.coding.ICoding;
import yoga.algo.coding.ICodingOperator;
import yoga.probability.Probablistics;

/**
 *
 * @author Yogev Montekyo
 */
public class BinaryStringCoding<T> implements ICoding<T>
{
    private BinaryString m_binaryString;

    public BinaryStringCoding(BinaryString binaryString)
    {
        m_binaryString = binaryString;
    }
    
    private int m_numberOfArguments;
    private int m_sizeOfArgument;

    public BinaryString getBinaryString()
    {
        return m_binaryString;
    }

    public void setNumberOfArguments(int m_numberOfArguments)
    {
        this.m_numberOfArguments = m_numberOfArguments;
    }

    public void setSizeOfArgument(int m_sizeOfArgument)
    {
        this.m_sizeOfArgument = m_sizeOfArgument;
    }

    public int getNumberOfArguments()
    {
        return m_numberOfArguments;
    }

    public int getSizeOfArgument()
    {
        return m_sizeOfArgument;
    }

    
    @Override
    public void mutate(MutationTypes mutationType, double probability) throws UnsupportedOperationException
    {
        if (mutationType.equals(MutationTypes.Single))
        {
            if (Probablistics.randomBoolean(probability))
            {
                m_binaryString.contaminateRandomBit();
            }
        }
        else if (mutationType.equals(MutationTypes.Multiple))
        {
            int numOfMutation = (int) (Probablistics.getRandomInt(m_binaryString.size()) * probability);

            while (numOfMutation-- > 0)
            {
                m_binaryString.contaminateRandomBit();
            }
        }
        else
        {
            throw new UnsupportedOperationException("Mutation type " + mutationType.toString() + " is not supported ");
        }

    }

    @Override
    public void crossWith(CrossingTypes crossingType, ICoding<T> coding) throws UnsupportedOperationException, IllegalArgumentException
    {
        if (!coding.getClass().isInstance(this))
        {
            throw new IllegalArgumentException("Type missmatch, cannot cross " + this.getClass().getName() + " with supplied coding reference");
        }

        BinaryStringCoding<T> binaryStringCoding = (BinaryStringCoding<T>) coding;

        if (crossingType.equals(CrossingTypes.Single))
        {
            int crossingIndex = Probablistics.getRandomInt(m_binaryString.size());
            m_binaryString.crossWith(binaryStringCoding.m_binaryString, crossingIndex);
        }
        else if (crossingType.equals(CrossingTypes.Double))
        {
            int firstCrossingIndex = Probablistics.getRandomInt(m_binaryString.size());
            m_binaryString.crossWith(binaryStringCoding.m_binaryString, firstCrossingIndex);

            int secondCrossingIndex = firstCrossingIndex + Probablistics.getRandomInt(m_binaryString.size() - firstCrossingIndex);
            m_binaryString.crossWith(binaryStringCoding.m_binaryString, secondCrossingIndex);
        }
    }

    @Override
    public void invert(InversionTypes inversionType) throws UnsupportedOperationException
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void reorder(OrderingTypes orderingType) throws UnsupportedOperationException
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void runOperator(ICodingOperator codingOperator) throws Exception
    {
        codingOperator.run(this);
    }

    @Override
    public String getDescription()
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public ICoding<T> getCopy()
    {
        BinaryStringCoding<T> coding = new BinaryStringCoding<T>(m_binaryString);
        coding.m_numberOfArguments = this.m_numberOfArguments;
        coding.m_sizeOfArgument = this.m_sizeOfArgument;                
        return coding;
    }

    @Override
    public int getSchemataHash()
    {
        int hash = 0;
        for (int i=0; i < m_binaryString.size(); i++)
        {
            hash += Math.pow(2,i);
        }
        
        return hash;
    }
}
